(function ($) {
    $.fn.yqCodeEdit = function (opts, param) {
        if (typeof opts == 'string') {
            try {
                return $.fn.yqCodeEdit.methods[opts](this, param);
            } catch (error) {
                console.log("yqCodeEdit", error);
                console.log(opts, param);
                
                return;
            }
        }

        return this.each(function () {
            try {
                $this = $(this);
                var opt;
                var $uniqueID;
                if ($this.data("yqtype") == "yqCodeEdit") {
                    $uniqueID = $this.attr("ID");
                    var opts_ = $.extend({}, options($this));
                    delete opt.data;
                    delete opt.editor;

                    destroy($this);
                    $this = $("#" + $uniqueID);
                    opt = $.extend(opts_, opts);
                }
                else {
                    opt = $.extend({}, $.fn.yqCodeEdit.defaults, opts);
                    $uniqueID = $this.attr("ID");
                    if ($uniqueID === undefined || $uniqueID === null || $uniqueID == "") {
                        $uniqueID = $.getUniqueID();
                        $this.attr("ID", $uniqueID);
                    }
                }

                if (opt.width === undefined && $this.width() > 0) {
                    opt.width = $this.width();
                }
                else if (typeof opt.width != "undefined") {
                    $this.width(opt.width);
                }

                if (opt.height === undefined && $this.height() > 0) {
                    opt.height = $this.height();
                }
                else if (typeof opt.height != "undefined") {
                    $this.height(opt.height);
                }

                if ($this[0].tagName.toLowerCase() != "div") {
                    var $uniqueID = $this.attr("id");
                    $this.removeAttr("id");
                    $this.after('<div id="' + $uniqueID + '" style="width: ' + opt.width + 'px;height:' + opt.height + 'px;"></div>')
                    $this.remove();
                    $this = $("#" + $uniqueID)
                }

                opt.onload = true;

                //变量信息
                $this.data("codeedit_opt", opt);
                $this.data("yqtype", "yqCodeEdit");

                var $object = $this;
                LoadJsCss(function () {
                    init_edit($object);
                });
            } catch (error) {
                console.log("yqCodeEdit", error);
                console.log(opts, param);
                return;
            }
        });
    };

    $.fn.yqCodeEdit.defaults = {
        types: ["base", "html", "javascript", "css", "json", "sql"],
        type: null,
        value: null,
        isEdit: true,   //可编辑
        theme:"chrome",
        fontSize: 14,
        // width: 400, //模态编辑器宽度 格式为 800（数字）
        // height: 300, //模态编辑器高度 格式为 600（数字）
        
        onChange: function (val) {//修改类型
            //console.log("ssssssss", val);
        },
        afterSetData:function(val){
           
        }
    };

    $.fn.yqCodeEdit.methods = {
        options: function (jq) {
            return options($(jq[0]));
        },
        destroy: function (jq) {
            destroy($(jq[0]));
        },
        resize: function (jq, width) {
            resize($(jq[0]), width);
        },

        setTheme:function(jq, theme){
           var opt= options($(jq[0]));
           opt.theme = theme;
           opt.editor.setTheme("ace/theme/" + theme);
        },

        openFind:function(jq){
            var opt= options($(jq[0]));
            opt.editor.execCommand("find")
         },


        clear: function (jq, data) {
            setValue($(jq[0]), null);
        },
        setValue: function (jq, value) {
            setValue($(jq[0]), value);
        },
        getValue: function (jq) {
            return getValue($(jq[0]));
        },
        setFontSize: function (jq, size) {
            setFontSize($(jq[0]), size);
        },
        disable: function (jq) {
            isEdit($(jq[0]), false);
        },
        enable: function (jq) {
            isEdit($(jq[0]), true);
        },
        getType: function (jq) {
            return getType($(jq[0]));
        },
    };

    function LoadJsCss(callback) {
        var file = [];
        file.push({ url: "/scripts/ace/ace.js", type: "js" });
        file.push({ url: "/scripts/ace/ext-language_tools.js", type: "js" });
        file.push({ url: "/scripts/crypto/sha256.min.js", type: "js" });
        yqLoadJsCss(file, function () {
            callback();
        })
    }

    function options($object) {
        return $object.data("codeedit_opt");
    }

    function destroy($object) {
        var opt = options($object);
        if (opt.data.length > 1) {
            var $p = $object.parent();
            $p.after($object);
            $p.find(".selectmode").combobox("destroy");
            $p.remove();
        }

        opt.editor.destroy();

        $object.empty();
        $object.removeClass("ace_editor");
        $object.removeClass("ace-tm");
        $object.css("border", "");

        $object.removeData("codeedit_opt");
        $object.removeData("yqtype");
    }

    function resize($object, params) {
        var opt = options($object);
        if (typeof params == "object") {
            opt.width = params.width;
            opt.height = params.height;
        }

        if (opt.data.length <= 1) {
            $object.width(opt.width);
            $object.height(opt.height);
        } else {
            $object.width(opt.width);
            $object.height(opt.height - 30);
        }

        opt.editor.resize()
    }

    function init_edit($object) {
        var opt = options($object);
        var $uniqueID = $object.attr('id');

        $object.css("border", "1px solid #efefef");

        if (opt.type === null || opt.type == "") {
            opt.type = ["base"];
        } else if (typeof opt.type == "string") {
            opt.type = [opt.type];
        }

        opt.data = [];
        for (let i = 0; i < opt.types.length; i++) {
            opt.data.push({ text: opt.types[i], value: opt.types[i] });
        }

        if (opt.data.length == 0) {
            opt.data.push({ text: "base", value: "base" });
        }

        if (opt.data.length == 1) {
            opt.editor = ace.edit($uniqueID);
        } else {
            var has_s = false;
            for (let i = 0; i < opt.data.length; i++) {
                if (opt.data[i].text == opt.type) {
                    opt.data[i]["selected"] = true;
                    has_s = true;
                    break;
                }
            }

            if (!has_s) {
                opt.data[0]["selected"] = true;
            }

            var $div = $("<div></div>")
            var $select = $('<select class="selectmode" style="width: 150px;"></select>');
            $object.wrap($div);
            $object.before($select);

            $object.height(opt.height - 33);
            opt.editor = ace.edit($uniqueID);

            $select.combobox({
                valueField: 'value',
                textField: 'text',
                data: opt.data,
                onChange: function (newValue, oldValue) {
                    $.yqLoadJsCss({ url: "/scripts/ace/mode-" + newValue + ".js", type: "js" },
                        function () {
                            opt.editor.session.setMode("ace/mode/" + newValue);
                        })
                }
            });
        }

        //设置高亮:
        opt.editor.setHighlightActiveLine(false);
        //设置代码折叠
        opt.editor.getSession().setUseWrapMode(true);
        //自动换行,设置为off关闭
        opt.editor.setOption("wrap", "free");
        //启用提示菜单
        ace.require("ace/ext/language_tools");
        opt.editor.setHighlightActiveLine(true); //代码高亮  
        opt.editor.setShowPrintMargin(false);
        opt.editor.setFontSize(opt.fontSize);
        opt.editor.setTheme("ace/theme/" + opt.theme);

        opt.editor.on("change", function (delta) {
            opt.onChange.call($object, opt.editor.getValue())
        });

        opt.onload = false;
        if (!(opt.value === undefined ||
            opt.value === null ||
            opt.value == "")) {
            setValue($object, opt.value);
        }
        isEdit($object, opt.isEdit);
    }

    function setValue($object, value) {
        var opt = options($object);

        if (!opt.onload) {
            setValueRun($object, value);
        }
        else {
            setTimeout(function () {
                setValue($object, value);
            }, 500);
        }
    }

    function setValueRun($object, value) {
        var opt = options($object);
        if (value === undefined || value == "") {
            value = null;
        }

        var mode = "base"
        if (opt.type == "html") {
            mode = "html";
        } else if (opt.type == "js") {
            mode = "javascript";
        } else if (opt.type == "css") {
            mode = "css";
        } else if (opt.type == "json") {
            mode = "json";
        } else if (opt.type == "xml") {
            mode = "xml";
        }
        var jsurl = "/scripts/ace/mode-" + mode + ".js";
        var modestr = "ace/mode/" + mode;

        $.yqLoadJsCss({ url: jsurl, type: "js" }, function () {
            opt.editor.session.setMode(modestr);
            opt.value = value;
            var cursor = opt.editor.selection.getCursor();
            opt.editor.setValue(value);
            opt.editor.gotoLine(cursor.row);
        })
    }

    function getValue($object) {
        var opt = options($object);
        return opt.editor.getValue();
    }

    function isEdit($object, tf) {
        var opt = options($object);
        opt.editor.setReadOnly(!tf);
    }

    function setFontSize($object, size) {
        var opt = options($object);
        if (size) {
            opt.fontSize = size;
        }
        opt.editor.setFontSize(opt.fontSize);
    }

    function getType($object) {
        var opt = options($object);
        if (opt.data.length == 1) {
            return opt.data[0].text;
        } else {
            var $p = $object.parent();
            return $p.find(".selectmode").combobox("getText");
        }
    }


    /**
   * 动态加载JS CSS
   * @param {string,Object,Array} file 脚本地址 url,{url:"2.css",type："css"},[{url:"2.css",type："css"}]
   * @param {function} callback  回调函数
   */
    function yqLoadJsCss(file, callback) {
        if (typeof file == "string") {
            loadFile(file,
                file.substring(file.lastIndexOf(".") + 1).toLowerCase(),
                function () {
                    if (typeof (callback) == 'function') {
                        callback();
                    }
                });
        } else if (typeof file == "object") {
            if (Array.isArray(file)) {
                if (file.length > 0) {
                    loadFiles(file, 0);
                }
            } else {
                loadFiles([file], 0);
            }
        } else {
            if (typeof (callback) == 'function') {
                callback();
            }
        }


        function loadFiles(file, i) {
            if (i >= file.length) {
                if (typeof (callback) == 'function') {
                    callback();
                }
                return;
            }

            if (file[i].type === undefined || file[i].type === null) {
                loadFile(file[i].url,
                    file[i].substring(file[i].lastIndexOf(".") + 1).toLowerCase(),
                    function () {
                        loadFiles(file, i + 1);
                    });
            } else {
                loadFile(file[i].url,
                    file[i].type,
                    function () {
                        loadFiles(file, i + 1);
                    });
            }
        }

        function loadFile(url, fileType, callback) {
            let fileHref;
            if (fileType == "js") {
                var scripts = $('script');
                for (let i = 0; i < scripts.length; i++) {
                    if ($(scripts[i]).attr("src") == url) {
                        callback();
                        return;
                    }
                }

                fileHref = document.createElement('script');
                fileHref.setAttribute("type", "text/javascript");
                fileHref.setAttribute("src", url);
            } else if (fileType == "css") {
                var links = $('link');
                for (let i = 0; i < links.length; i++) {
                    if ($(links[i]).attr("href") == url) {
                        if (typeof (callback) == 'function') {
                            callback();
                        }
                        return;
                    }
                }

                fileHref = document.createElement('link');
                fileHref.setAttribute("rel", "stylesheet");
                fileHref.setAttribute("type", "text/css");
                fileHref.setAttribute("href", url);
            }

            if (fileHref !== undefined) {
                document.getElementsByTagName("head")[0].appendChild(fileHref);
                if (typeof (callback) == 'function') {
                    fileHref.onload = function () {
                        if (!this.readyState || this.readyState == 'loaded'
                            || this.readyState == 'complete') {
                            callback();
                        }
                    }
                }
            } else {
                if (typeof (callback) == 'function') {
                    callback();
                }
            }
        }
    }

})(jQuery);